/*
 * JOGRE (Java Online Gaming Real-time Engine) - Spades
 * Copyright (C) 2004  Bob Marks (marksie531@yahoo.com)
 * http://jogre.sourceforge.org
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
package org.jogre.mayi.client;

import java.awt.Component;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;

import org.jogre.client.JogreController;
import org.jogre.client.awt.JogreComponent;
import org.jogre.common.Player;
import org.jogre.common.PlayerList;
import org.jogre.common.comm.CommNextPlayer;
import org.jogre.common.games.Card;
import org.jogre.mayi.common.CommMayIDiscard;
import org.jogre.mayi.common.CommMayIDrawCard;
import org.jogre.mayi.common.CommMayIHandScore;
import org.jogre.mayi.common.CommMayIMayI;
import org.jogre.mayi.common.CommMayIPlayCards;
import org.jogre.mayi.common.CommMayIRequestDeal;
import org.jogre.mayi.common.MayIDeal;
import org.jogre.mayi.server.MayIConstants;

/**
 * @author Garrett Lehman (Gman)
 * @version Alpha 0.2.3
 *
 * Controller for the spades game.
 */
public class MayIController extends JogreController {

	// Spades model
	protected MayIModel model;

	// Spades player component
	protected MayIPlayerHandComponent [] playerHandComponents;
	protected MayIPlayerHandComponent playerHandComponent;
	
	protected MayIDeckComponent deckComponent;
	
	protected MayIPlayAreaComponent [][] playComponents;
	
	private Component componentPressed = null;
	
	

	/**
	 * Contructor for initializing the controller
	 *
	 * @param gameModel
	 * @param boardComponent
	 */
	public MayIController(MayIModel model,
			MayIPlayerHandComponent [] handComponents,
			MayIDeckComponent deckComponent,
			MayIPlayAreaComponent [][] playComponents) {
		super(model, (JogreComponent) handComponents[0]);
		this.model = model;
		this.playerHandComponents = handComponents;
		this.playerHandComponent = handComponents[0];
		this.deckComponent = deckComponent;
		this.playComponents = playComponents;
	}

	/**
	 * Start the controller
	 *
	 * @see org.jogre.common.JogreModel#start()
	 */
	public void start() {

		model.reset();

		requestDeal();
		
		nextPlayer();
	}

	/**
	 * Record mouse presses for selecting cards
	 *
	 * @see java.awt.event.MouseListener#mousePressed(java.awt.event.MouseEvent)
	 */
	public void mousePressed(MouseEvent e) {

		componentPressed = e.getComponent();
		
		// if playing and current turn, record mouse press
		if (isGamePlaying() && isThisPlayersTurn()
				&& this.model.getGameState() == MayIModel.GAME_STATE_PLAYING) {
			int mouseX = e.getX();
			int mouseY = e.getY();
			
			if (e.getComponent().equals(this.playerHandComponent)) {
				this.playerHandComponent.press(mouseX, mouseY);
			}
		}
	}

	/**
	 * Record mouse clicks for selecting cards
	 *
	 * @see java.awt.event.MouseListener#mouseReleased(java.awt.event.MouseEvent)
	 */
	public void mouseReleased(MouseEvent e) {

		if (!e.getComponent().equals(this.componentPressed)) {
			return;
		}
		
		int mouseX = e.getX();
		int mouseY = e.getY();
		
		// if playing and current turn, record mouse click
		if (isGamePlaying() && isThisPlayersTurn()
				&& this.model.getGameState() == MayIModel.GAME_STATE_PLAYING) {
			
			if (e.getComponent().equals(this.playerHandComponent)) {
				this.playerHandComponent.click(mouseX, mouseY);
			}
			else if (e.getComponent().equals(this.deckComponent)) {
				if ((mouseX > (Card.CARD_PIXEL_WIDTH+10) && mouseX < (2*Card.CARD_PIXEL_WIDTH+10)
						&& mouseY > 5 && mouseY < (Card.CARD_PIXEL_HEIGHT+5)) 
						&& (this.playerHandComponent.getCardsClicked().size() == 1)) {
					
					if (this.isInitialPlayValid()) {
						Card c = this.playerHandComponent.getCardsClicked().get(0);
						this.deckComponent.addDiscard(c);
						this.playerHandComponent.moveClicked();
						
						CommMayIDiscard sendDiscard = new CommMayIDiscard(conn.getUsername(), c);
						
						
						List<CommMayIPlayCards> plays = new ArrayList<CommMayIPlayCards>();
						for (int i = 0; i < this.playComponents.length; i++) {
							for (int j = 0; j < this.playComponents[i].length; j++) {
								List<Card> cards = this.playComponents[i][j].getNewCardsAdded();
								if (!cards.isEmpty()) {
									String playUser = null;
									for (int k = 0; k < this.getTable().getNumOfPlayers(); k++) {
										if (i == model.getSeatIndex(this.getTable().getPlayerList().getPlayer(k).getSeatNum())) {
											playUser = this.getTable().getPlayerList().getPlayer(k).getUser().getUsername();
										}
									}
									plays.add(new CommMayIPlayCards(this.getCurrentPlayer(), playUser, j, cards));
								}
							}
						}
						sendDiscard.setPlayedCards(plays);
						
						
						if (this.playerHandComponent.isOut()) {
							//countScores();
							sendDiscard.setOut();
						}
						else {
							//this.model.setGameState(MayIModel.GAME_STATE_WAITING_TO_PLAY);
							//this.nextPlayer();
						}
						
						conn.send(sendDiscard);
						
						if (sendDiscard.getOut()) {
							CommMayIHandScore score = new CommMayIHandScore(
									conn.getUsername(), 
									this.playerHandComponent.getPoints());
							conn.send(score);
						}
					}
					
					
				}
			}
			else {
				for (int i = 0; i < this.getTable().getNumOfPlayers(); i++) {
					for (int j = 0; j < MayIConstants.PLAY_AREAS; j++) {
						MayIPlayAreaComponent c = this.playComponents[i][j];
						if (e.getComponent().equals(c)) {
							if (i == 0 || isInitialPlayValid()) {
								boolean valid = c.playCards(this.playerHandComponent.getCardsClicked());
								if (valid) {
									this.playerHandComponent.moveClicked();
								}
							}
						}
					}
				}
			}
		}
		else if (isGamePlaying() && isThisPlayersTurn()
				&& this.model.getGameState() == MayIModel.GAME_STATE_PRE_TURN) {
			
			if (e.getComponent().equals(this.deckComponent)) {
				if (mouseX > 5 && mouseX < (Card.CARD_PIXEL_WIDTH+5)
						&& mouseY > 5 && mouseY < (Card.CARD_PIXEL_HEIGHT+5)) {
					
					if (!model.getMayIReceived().isEmpty()) {
						int smallIndex = this.getTable().getNumOfPlayers();
						String smallUser = null;
						
						for (String p : model.getMayIReceived()) {
							int index = model.getSeatIndex(this.getPlayerFromTable(p).getSeatNum());
							if (index < smallIndex) {
								smallIndex = index;
								smallUser = p;
							}
						}
						
						Card c1 = this.deckComponent.drawFromDeck();
						this.playerHandComponents[smallIndex].addCard(c1);
						Card c2 = this.deckComponent.drawDiscard();
						this.playerHandComponents[smallIndex].addCard(c2);
						
						CommMayIDrawCard sendDraw1 = new CommMayIDrawCard(conn.getUsername(), CommMayIDrawCard.FROM_DECK);
						sendDraw1.setDrawUser(smallUser);
						conn.send(sendDraw1);
						CommMayIDrawCard sendDraw2 = new CommMayIDrawCard(conn.getUsername(), CommMayIDrawCard.FROM_DISCARD);
						sendDraw2.setDrawUser(smallUser);
						conn.send(sendDraw2);
						
						model.resetMayIReceived();
					}
					
					
					Card c = this.deckComponent.drawFromDeck();
					this.playerHandComponent.addCard(c);
					this.model.setGameState(MayIModel.GAME_STATE_PLAYING);
					CommMayIDrawCard sendDraw = new CommMayIDrawCard(conn.getUsername(), CommMayIDrawCard.FROM_DECK);
					conn.send(sendDraw);
				}
				else if (mouseX > (Card.CARD_PIXEL_WIDTH+10) && mouseX < (2*Card.CARD_PIXEL_WIDTH+10)
						&& mouseY > 5 && mouseY < (Card.CARD_PIXEL_HEIGHT+5)) {
					Card c = this.deckComponent.drawDiscard();
					this.playerHandComponent.addCard(c);
					this.model.setGameState(MayIModel.GAME_STATE_PLAYING);
					CommMayIDrawCard sendDraw = new CommMayIDrawCard(conn.getUsername(), CommMayIDrawCard.FROM_DISCARD);
					conn.send(sendDraw);
				}
			}
		}
	}

	
	public void requestDeal() {
		CommMayIRequestDeal requestHand = new CommMayIRequestDeal(conn
				.getUsername());
		conn.send(requestHand);
	}

	/**
	 * Get player from table by username
	 *
	 * @param username Username
	 * @return player from table by username
	 */
	public Player getPlayerFromTable(String username) {
		PlayerList playerList = this.getTable().getPlayerList();
		return playerList.getPlayer(username);
	}
	
	
	public void nextPlayer () {
		// Create communcations table action of type "Next Player".
		CommNextPlayer nextPlayer = new CommNextPlayer ();

		// Fix for bug 1176951 - "Possibility of consequent moves"
		conn.getTable().getPlayerList().setCurrentPlayer (PlayerList.NO_PLAYER);

		// send to server from client
		this.conn.send (nextPlayer);
	}
	
	public boolean isInitialPlayValid() {
		boolean valid = true;
		boolean didPlay = false;
		for (int i = 0; i < this.playComponents[0].length; i++) {
			didPlay = didPlay || this.playComponents[0][i].didPlay();
			if (this.playComponents[0][i].getType() >= 0 && !this.playComponents[0][i].valid()) {
				valid = false;
			}
		}
		return !didPlay || valid;
	}
	
	public void callMayI() {
		System.out.println("MayI button pressed");
		
		//Card c1 = this.deckComponent.drawDiscard();
		//this.playerHandComponent.addCard(c1);
		//Card c2 = this.deckComponent.drawFromDeck();
		//this.playerHandComponent.addCard(c2);
		
		CommMayIMayI mayi = new CommMayIMayI(conn.getUsername());
		this.conn.send (mayi);
	}
	
	public void unplayCards() {
		
		System.out.println("Unplay button pressed");
		
		for (int i = 0; i < this.getTable().getNumOfPlayers(); i++) {
			for (int j = 0; j < MayIConstants.PLAY_AREAS; j++) {
				MayIPlayAreaComponent comp = this.playComponents[i][j];
				for (Card c : comp.unplayCards()) {
					this.playerHandComponent.addCard(c);
				}
			}
		}
	}
	
	public void receiveMayI(CommMayIMayI mayi) {
		if (model.getGameState() == MayIModel.GAME_STATE_PRE_TURN) {
			model.addMayIReceived(mayi.getUsername());
		}
	}

}